﻿package com.util.textProcess;

import java.lang.reflect.Field;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: DBUtil.java
 * @Description: 基于JDBC的数据库操作的轻量封装 使用时需要添加相应的依赖包（目前仅支持MySQL） 只提供了CURD四种基本操作
 *               不提供连接池，SQL注入保护，事务管理等高级操作 只是适用于简单的DEMO中使用，并不建议在大型任务中使用
 *               本模块使用约定命名的形式对数据库进行操作 数据表的命名约定为实体类名的小写形式，如：实体类（Document） ->
 *               数据库表（document） 数据列的命名约定为实体类的实例属性名，如：实例属性（docId） -> 数据库列（docId）
 * @author ZFly
 * @version V1.1
 * @Date 2015/11/06
 */
public abstract class DBUtil<T> {

	protected static Statement stmt = null;
	public static boolean showSql = false;
	protected Class<?> clazz = this.getClass();
	protected Field[] fields = this.getClass().getDeclaredFields();
	private String primaryKey = "id";

	/**
	 * @Description 初始化数据库连接，此方法必须在使用该模版前调用 ，且仅需调用一次 若连接失败则无法执行后续操作，如
	 *              DBUtil.conn("MySQL",
	 *              "jdbc:mysql://121.42.151.185:3306/sh?characterEncoding=utf8"
	 *              , "root", "123456");
	 */
	public static boolean conn(String dataBase, String url, String usr,
			String pwd) {
		try {
			if (DBUtil.stmt != null)
				return false;
			if (dataBase.toLowerCase().equals("DBUtil")) {
				System.out.println("call me 小黄君");
				return false;
			}
			if (dataBase.toLowerCase().equals("mysql")) {
				Class.forName("com.mysql.jdbc.Driver");
			}
			DBUtil.stmt = DriverManager.getConnection(url, usr, pwd)
					.createStatement();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * @Description 设置主键，使用此模版的实体类必须拥有一个int类型的主键， 并且在数据库中将主键设置为自增模式
	 *              默认值为"id"，可在实体类构造函数中修改，如 public EntityClass(){
	 *              setPrimaryKey("keyName"); }
	 */
	protected void setPrimaryKey(String keyName) {
		primaryKey = keyName;
	}

	@SuppressWarnings("unchecked")
	public List<T> find(T entity) throws Exception {
		/* 连接初始化检查 */
		if (stmt == null)
			return null;

		boolean need_separator = false; /* 是否需要分隔符 */
		boolean need_where = true; /* 是否需要关键词WHERE */
		/* 构造SQL查询语句 */
		String sql = "SELECT * FROM " + clazz.getSimpleName().toLowerCase();
		for (Field f : fields) {
			Object value = f.get(entity);
			String name = f.getName();
			if (name.equals(primaryKey))
				continue;
			if (value != null && !value.equals(0)) {
				if (need_where) {
					sql += " WHERE ";
					need_where = false;
				}
				if (need_separator) {
					sql += " AND ";
				}
				sql += name + "='" + value + "'";
				need_separator = true;

			} else {
				need_separator = false;
			}
		}

		ResultSet rs = executeSQL(sql);
		if (rs == null)
			return null;

		/* 解析SQL查询结果 */
		List<T> list = new ArrayList<T>();
		while (rs.next()) {
			Object obj = clazz.newInstance();
			for (Field f : fields) {
				f.set(obj, rs.getObject(f.getName()));
			}
			list.add((T) obj);
		}
		return list;
	}

	public void save() throws Exception {
		/* 连接初始化检查 */
		if (stmt == null)
			return;

		boolean need_separator = false;
		/* 构造SQL插入语句 */
		String sql_mark = "INSERT INTO " + clazz.getSimpleName().toLowerCase()
				+ " (";
		String sql_value = ") VALUES (";
		String sql = "";

		for (Field f : fields) {
			String name = f.getName();
			Object value = f.get(this);
			if (name.equals(primaryKey))
				continue; /* 主键由数据库自动递增 */
			if (value == null || value.equals(0))
				continue;
			if (need_separator) {
				sql_mark += ",";
				sql_value += ",";
			} else
				need_separator = true;
			sql_mark += f.getName();
			sql_value += "'" + f.get(this) + "'";
		}
		sql = sql_mark + sql_value + ")";
		if (showSql)
			System.out.println("save\t: " + sql);

		executeSQL(sql);

		/* 更新实体类主键 */
		sql = "SELECT " + primaryKey + " FROM "
				+ clazz.getSimpleName().toLowerCase() + " ORDER BY "
				+ primaryKey + " DESC";
		ResultSet rs = DBUtil.stmt.executeQuery(sql);
		rs.next();
		clazz.getField(primaryKey).set(this, rs.getObject(primaryKey));
	}

	public void update() throws Exception {
		/* 连接初始化检查 */
		if (stmt == null)
			return;

		boolean need_separator = false;
		/* 构造SQL更新语句 */
		String sql = "UPDATE " + clazz.getSimpleName().toLowerCase() + " SET ";
		for (Field f : fields) {
			Object value = f.get(this);
			String name = f.getName();
			if (name.equals(primaryKey))
				continue; /* 主键由数据库自动递增 */
			if (value == null || value.equals(0))
				continue;
			if (need_separator)
				sql += ",";
			else
				need_separator = true;
			sql += name + "='" + value + "'";
		}
		sql += " WHERE " + primaryKey + "='"
				+ clazz.getDeclaredField(primaryKey).getInt(this) + "'";

		executeSQL(sql);
	}

	public void delete() throws Exception {
		/* 连接初始化检查 */
		if (stmt == null)
			return;

		Field field = clazz.getDeclaredField(primaryKey);
		/* 构造SQL删除语句 */
		String sql = "DELETE FROM " + clazz.getSimpleName().toLowerCase()
				+ " WHERE " + primaryKey + "='" + field.getInt(this) + "'";

		executeSQL(sql);
	}

	public ResultSet executeSQL(String sql) throws Exception {
		if (showSql)
			System.out.println(sql);
		if (DBUtil.stmt.execute(sql))
			return DBUtil.stmt.getResultSet();
		return null;
	}
}
